Skip to contentMethod: findAllSolutions(Set, boolean)
      1: package de.fhdw.gaming.ipspiel23.c4.domain.impl.evaluation;
2: 
3: import java.util.Set;
4: 
5: import de.fhdw.gaming.ipspiel23.c4.domain.C4Direction;
6: import de.fhdw.gaming.ipspiel23.c4.domain.IC4SolutionSlim;
7: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim;
8: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4SolutionSlim;
9: 
10: import static de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim.EMPTY_TOKEN;
11: 
12: /**
13:  * A {@link C4SolutionAnalyzer} that analyzes the board on the diagonal from the bottom left to the top right.
14:  */
15: public class C4SolutionAnalyzerDiagonalLeft extends C4SolutionAnalyzerDiagonal {
16: 
17:     /**
18:      * Creates a new {@link C4SolutionAnalyzerDiagonalLeft}.
19:      * @param board The board to analyze.
20:      */
21:     public C4SolutionAnalyzerDiagonalLeft(final C4BoardSlim board) {
22:         super(board, C4Direction.NORTH_EAST);
23:     }
24: 
25:     @Override
26:     public IC4SolutionSlim tryFindFirstSolution(final IC4SolutionSlim currentSolution, final boolean updateCache) {
27:         // "Assignment of parameter 'currentSolution' is not allowed." :P
28:         IC4SolutionSlim solution = currentSolution;
29:         
30:         int iteration = 0;
31:         // determine start row of column 0 (skip first targetCount rows)
32:         for (int startRow = targetCount(); solution == null && startRow < rowMax(); startRow++, iteration++) {
33:             if (mayContainSolution(iteration)) {
34:                 solution = tryFindFirstSolution(startRow, 0, iteration, updateCache);
35:             }
36:         }
37:         // determine start column of last row (ignore last targetCount columns)
38:         // don't evaluate diagonal starting in bottom left twice (startCol = 1)
39:         for (int startCol = 1; solution == null && startCol < colMax() - targetCount(); startCol++, iteration++) {
40:             if (mayContainSolution(iteration)) {
41:                 solution = tryFindFirstSolution(rowMax() - 1, startCol, iteration, updateCache);
42:             }
43:         }
44:         return solution;
45:     }
46:     
47:     /**
48:      * Lazily searches for the first solution on the board starting at the specified position.
49:      * @param startRow the row to start at
50:      * @param startCol the column to start at
51:      * @param iteration the current iteration of the search
52:      * @param updateCache whether to update the solution cache, preventing the same line to be checked again
53:      * @return The first solution on the board or null if no solution was found.
54:      */
55:     private IC4SolutionSlim tryFindFirstSolution(final int startRow, final int startCol,
56:             final int iteration, final boolean updateCache) {
57:         int count = 0;
58:         int lastToken = 0;
59:         // "ForLoopVariableCount: Too many control variables in the for statement" :P
60:         int row = startRow;
61:         int col = startCol;
62:         boolean isDiagonalFull = true;
63:         for (; row >= 0 && col < colMax(); row--, col++) {
64:             final int token = board().getTokenUnsafe(row, col);
65:             count = countConsecutivesBranchless(count, token, lastToken);
66:             if (count >= targetCount()) {
67:                 return scanRemaining(token, row, col);
68:             }
69:             isDiagonalFull &= token != EMPTY_TOKEN;
70:             lastToken = token;
71:         }
72:         if (updateCache && isDiagonalFull) {
73:             noSolutionIn(iteration);
74:         }
75:         return null;
76:     }
77: 
78:     @Override
79:     public void findAllSolutions(final Set<IC4SolutionSlim> resultSet, final boolean updateCache) {
80: 
81:         int iteration = 0;
82:         // determine start row of column 0 (skip first targetCount rows)
83:•        for (int startRow = targetCount(); startRow < rowMax(); startRow++, iteration++) {
84:•            if (mayContainSolution(iteration)) {
85:                 findAllSolutions(resultSet, startRow, 0, iteration, updateCache);
86:             }
87:         }
88:         // determine start column of last row (ignore last targetCount columns)
89:         // don't evaluate diagonal starting in bottom left twice (startCol = 1)
90:•        for (int startCol = 1; startCol < colMax() - targetCount(); startCol++, iteration++) {
91:•            if (mayContainSolution(iteration)) {
92:                 findAllSolutions(resultSet, rowMax() - 1, startCol, iteration, updateCache);
93:             }
94:         }
95:     }
96:     
97:     /**
98:      * Eagerly searches for all solutions on the board starting at the specified position.
99:      * @param startRow the row to start at
100:      * @param startCol the column to start at
101:      * @param iteration the current iteration of the search
102:      * @param updateCache whether to update the solution cache, preventing the same line to be checked again
103:      * @param resultSet the set to which any solutions are added
104:      */
105:     private void findAllSolutions(final Set<IC4SolutionSlim> resultSet, final int startRow, 
106:             final int startCol, final int iteration, final boolean updateCache) {
107:         int count = 0;
108:         int lastToken = 0;
109:         int row = startRow;
110:         int col = startCol;
111:         boolean isDiagonalFull = true;
112:         boolean diagonalContainsSolution = false;
113:         for (; row >= 0 && col < colMax(); row--, col++) {
114:             final int token = board().getTokenUnsafe(row, col);
115:             count = countConsecutivesBranchless(count, token, lastToken);
116:             if (count >= targetCount()) {
117:                 count = 0;
118: 
119:                 final C4SolutionSlim solution = scanRemaining(token, row, col);
120:                 resultSet.add(solution);
121:                 diagonalContainsSolution = true;
122:                 // skip to end of solution
123:                 row = solution.getRowIndexEnd();
124:                 col = solution.getColumnIndexEnd();
125:             }
126:             isDiagonalFull &= token != EMPTY_TOKEN;
127:             lastToken = token;
128:         }
129:         if (updateCache && isDiagonalFull && !diagonalContainsSolution) {
130:             noSolutionIn(iteration);
131:         }
132:     }
133:     
134:     @Override
135:     protected C4SolutionSlim scanRemaining(final int token, final int startRow, final int startCol) {
136:         int row = startRow - 1;
137:         int col = startCol + 1;
138:         while (row >= 0 && col < colMax() && board().getTokenUnsafe(row, col) == token) {
139:             row--; 
140:             col++;
141:         }
142:         // revert last change to get inclusive upper bound
143:         row++;
144:         col--;
145:         // determine true solution size
146:         return solutionOf(token, row, col, board().getMinimumSolutionSize() + col - startCol);
147:     }
148: }